from ogreEx.blender.types import Operator
from ogreEx.ui.UIClass import OPERATOR

@OPERATOR
class bpyShaders(Operator):
    '''operator: enables material nodes (workaround for not having IDPointers in pyRNA)'''
    bl_idname = "ogre.force_setup_material_passes"
    bl_label = "force bpyShaders"
    bl_options = {'REGISTER'}

    @classmethod
    def poll(cls, context):
        if context.active_object and context.active_object.active_material: return True
    def invoke(self, context, event):
        mat = context.active_object.active_material
        mat.use_material_passes = True
        bpyShaders.create_material_passes( mat )
        return {'FINISHED'}


    ## setup from MaterialScripts.reset_rna( callback=bpyShaders.on_change_parent_material )
    @staticmethod
    def on_change_parent_material(mat,context):
        print(mat,context)
        print('callback', mat.ogre_parent_material)

    @staticmethod
    def get_subnodes(mat, type='TEXTURE'):
        d = {}
        for node in mat.nodes:
            if node.type==type: d[node.name] = node
        keys = list(d.keys())
        keys.sort()
        r = []
        for key in keys: r.append( d[key] )
        return r


    @staticmethod
    def get_texture_subnodes( parent, submaterial=None ):
        if not submaterial: submaterial = parent.active_node_material
        d = {}
        for link in parent.node_tree.links:
            if link.from_node and link.from_node.type=='TEXTURE':
                if link.to_node and link.to_node.type == 'MATERIAL_EXT':
                    if link.to_node.material:
                        if link.to_node.material.name == submaterial.name:
                            node = link.from_node
                            d[node.name] = node
        keys = list(d.keys())           # this breaks if the user renames the node - TODO improve me
        keys.sort()
        r = []
        for key in keys: r.append( d[key] )
        return r

    @staticmethod
    def get_connected_input_nodes( material, node ):
        r = []
        for link in material.node_tree.links:
            if link.to_node and link.to_node.name == node.name:
                r.append( link.from_node )
        return r

    @staticmethod
    def get_or_create_material_passes( mat, n=8 ):
        if not mat.node_tree:
            print('CREATING MATERIAL PASSES', n)
            bpyShaders.create_material_passes( mat, n )

        d = {}      # funky, blender259 had this in order, now blender260 has random order
        for node in mat.node_tree.nodes:
            if node.type == 'MATERIAL_EXT' and node.name.startswith('GEN.'):
                d[node.name] = node
        keys = list(d.keys())
        keys.sort()
        r = []
        for key in keys: r.append( d[key] )
        return r

    @staticmethod
    def get_or_create_texture_nodes( mat, n=6 ):    # currently not used
        #print('bpyShaders.get_or_create_texture_nodes( %s, %s )' %(mat,n))
        assert mat.node_tree    # must call create_material_passes first
        m = []
        for node in mat.node_tree.nodes:
            if node.type == 'MATERIAL_EXT' and node.name.startswith('GEN.'):
                m.append( node )
        if not m:
            m = bpyShaders.get_or_create_material_passes(mat)
        print(m)
        r = []
        for link in mat.node_tree.links:
            print(link, link.to_node, link.from_node)
            if link.to_node and link.to_node.name.startswith('GEN.') and link.from_node.type=='TEXTURE':
                r.append( link.from_node )
        if not r:
            print('--missing texture nodes--')
            r = bpyShaders.create_texture_nodes( mat, n )
        return r


    @staticmethod
    def create_material_passes( mat, n=8, textures=True ):
        #print('bpyShaders.create_material_passes( %s, %s )' %(mat,n))
        mat.use_nodes = True
        tree = mat.node_tree	# valid pointer now

        nodes = bpyShaders.get_subnodes( tree, 'MATERIAL' )  # assign base material
        if nodes and not nodes[0].material:
            nodes[0].material = mat

        r = []
        x = 680
        for i in range( n ):
            node = tree.nodes.new( type='MATERIAL_EXT' )
            node.name = 'GEN.%s' %i
            node.location.x = x; node.location.y = 640
            r.append( node )
            x += 220
        #mat.use_nodes = False  # TODO set user material to default output
        if textures:
            texnodes = bpyShaders.create_texture_nodes( mat )
            print( texnodes )
        return r

    @staticmethod
    def create_texture_nodes( mat, n=6, geoms=True ):
        #print('bpyShaders.create_texture_nodes( %s )' %mat)
        assert mat.node_tree    # must call create_material_passes first
        mats = bpyShaders.get_or_create_material_passes( mat )
        r = {}; x = 400
        for i,m in enumerate(mats):
            r['material'] = m; r['textures'] = []; r['geoms'] = []
            inputs = []     # other inputs mess up material preview #
            for tag in ['Mirror', 'Ambient', 'Emit', 'SpecTra', 'Ray Mirror', 'Translucency']:
                inputs.append( m.inputs[ tag ] )
            for j in range(n):
                tex = mat.node_tree.nodes.new( type='TEXTURE' )
                tex.name = 'TEX.%s.%s' %(j, m.name)
                tex.location.x = x - (j*16)
                tex.location.y = -(j*230)
                input = inputs[j]; output = tex.outputs['Color']
                link = mat.node_tree.links.new( input, output )
                r['textures'].append( tex )

                if geoms:
                    geo = mat.node_tree.nodes.new( type='GEOMETRY' )
                    link = mat.node_tree.links.new( tex.inputs['Vector'], geo.outputs['UV'] )
                    geo.location.x = x - (j*16) - 250
                    geo.location.y = -(j*250) - 1500
                    r['geoms'].append( geo )
            x += 220
        return r